using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace TamTam.SharePoint.SolutionManagement {
    
    /// <summary>
    /// Handles the deployment of a sharepoint solution on the local sharepoint farm
    /// </summary>
    internal class SolutionHandler {

        /// <summary>
        /// This gives us access to the elevated code runner staticly
        /// </summary>
        /// <param name="solutionName"></param>
        /// <param name="fileData"></param>
        /// <param name="deploymentType"></param>
        public static void Deploy(
            string solutionName, 
            byte[] fileData,
            MsBuildTasks.Deployment deploymentType) {

            string error;

            if (solutionName != null) {
                if (solutionName.ToLower().EndsWith(".wsp")) {
                    if (!System.IO.Directory.Exists(@"c:\windows\temp\ttsm\")) {
                        System.IO.Directory.CreateDirectory(@"c:\windows\temp\ttsm\");
                    }
                    string solutionFileName = System.IO.Path.Combine(@"c:\windows\temp\ttsm\", solutionName);
                    if (System.IO.File.Exists(solutionFileName)) {
                        System.IO.File.Delete(solutionFileName);
                    }
                    // write the bytearray to a file
                    using (System.IO.FileStream fs = new System.IO.FileStream(solutionFileName, System.IO.FileMode.CreateNew, System.IO.FileAccess.Write)) {
                        fs.Write(fileData, 0, fileData.GetLength(0));
                    }
                    // clear the byte array
                    fileData = null;

                    SPSolution newsolution = null;

                    bool exists = false;
                    try {
                        // can we add this solution?
                        newsolution = SPFarm.Local.Solutions.Add(solutionFileName);
                    }
                    catch (ArgumentException exc) {
                        //it already exists?
                        exists = true;
                        error = exc.Message;
                    }
                    if (exists) { 
                        // we should try and upgrade or replace the solution then
                        try {
                            Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("{0} exists.", solutionName));
                            newsolution = SPFarm.Local.Solutions[solutionName];
                            if (deploymentType == MsBuildTasks.Deployment.Replace) {
                                Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("Replacing {0}.", solutionName));
                                if (newsolution.Deployed) {
                                    // we need to copy this collection,
                                    // we are going to redeploy the solution to these webapps
                                    Collection<SPWebApplication> webapps = new Collection<SPWebApplication>();
                                    foreach (SPWebApplication webapp in newsolution.DeployedWebApplications) {
                                        webapps.Add(webapp.Clone() as SPWebApplication);
                                    }

                                    // retract it
                                    newsolution.Retract(DateTime.Now, webapps);
                                    // wait 15secs
                                    System.Threading.Thread.Sleep(29 * 1000);
                                    Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("Retracted {0}.", solutionName));
                                    // remove it completly
                                    newsolution.Delete();
                                    // add it cleanly
                                    Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("Added new {0}.", solutionName));
                                    // redeploy is
                                    newsolution = SPFarm.Local.Solutions.Add(solutionFileName);
                                    newsolution.Deploy(DateTime.Now, true, webapps, true);
                                    Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("Deployed {0} to {1} WebApps.", solutionName,newsolution.DeployedWebApplications.Count));
                                    // clean up?                                    
                                    webapps.Clear();
                                }
                                else {
                                    // it is not deployed so just remove it completly
                                    newsolution.Delete();
                                    // add it cleanly, no deployment
                                    SPFarm.Local.Solutions.Add(solutionFileName);
                                }
                            }
                            else {
                                // no replace, but an inplace upgrade
                                if (newsolution != null) {
                                    Diagnostics.Logging.LogMessage("SolutionManagement", "DeploySolution", string.Format("Upgrading {0} to {1} WebApps.", solutionName, newsolution.DeployedWebApplications.Count));
                                    newsolution.Upgrade(solutionFileName);
                                    error = "";
                                }
                            }
                        }
                        catch (InvalidOperationException exc) {
                            error = exc.Message;
                        }
                    }
                    if (System.IO.File.Exists(solutionFileName)) {
                        System.IO.File.Delete(solutionFileName);
                    }
                }
            }
        }
    }
}
